# -*- coding: utf8 -*-

import sys
import os
import gtk
import gobject
import json
from time import time, sleep
from datetime import timedelta
from pprint import pprint
import widgets
from send2trash import send2trash

from service.task import TaskManager

print("Python version: %r" % (sys.version,) )
print("GTK+ version: %r" % (gtk.gtk_version,) )
print("PyGTK version: %r" % (gtk.pygtk_version,) )

class Main( object ):
    
    _options = None
    
    _thread_ui = None
    _thread_ui_run = True
    
    _ui = None
    _ui_title = None

    _task_manager = None
    
    _last_stats = None

    _file_prog = None
    _file_lbl = None

    _archive_prog = None
    _archive_lbl = None

    _th_dup_images = None
    _th_dup_arch = None

    def __init__( self ):
        self._options = {
            "ui_file" : "resource/ui.glade",
            "filter_in" : ["*.*"],
            "filter_out" : ["*.db"],
            "temp_directory" : ".",
            "delete_to_trash" : 1,
            "hash_function" : "md5",
            "directories" : []
        }

        self._task_manager = TaskManager()

        self._last_stats = {}

        self._file_prog = {}
        self._file_lbl = {}

        self._archive_prog = {}
        self._archive_lbl = {}

        self._started = False
        
    def get_option( self, name ):
        return self._options[ name ]

    def getTaskManager(self):
        return self._task_manager

    def get_stats( self ):
        return self.getTaskManager().get_request().getStatistics()

    def get_db( self ):
        return self.getTaskManager().get_request().getDatabase()

    def format_file_size( self, size ):
        """
        @rtype: tuple
        """
        u = "Б"
        if size > 1024:
            size /= 1024.0
            u = "КиБ"
        if size > 1024:
            size /= 1024.0
            u = "МиБ"
        if size > 1024:
            size /= 1024.0
            u = "ГиБ"
        if size > 1024:
            size /= 1024.0
            u = "ТиБ"
        return size, u
    
    def format_file_size_si( self, size ):
        """
        @rtype: tuple
        """
        u = "Б"
        if size > 1000:
            size /= 1000.0
            u = "КБ"
        if size > 1000:
            size /= 1000.0
            u = "МБ"
        if size > 1000:
            size /= 1000.0
            u = "ГБ"
        if size > 1000:
            size /= 1000.0
            u = "ТБ"
        return size, u


    def get_hash_algs(self):

        algs = [
            'md2', 'md4', 'md5', 'md6',
            'sha1', 'sha256', 'sha512',
            'ripemd160', 'ripemd320',
            'tiger', 'whirlpool'
        ]

        import hashlib

        support = []
        for alg in algs:
            try:
                hashlib.new(alg)
                support.append(alg)
            except:
                pass

        return support


    def get_ui( self ):
        """
        @rtype: gtk.Builder
        """
        if self._ui is None:
            self._ui = gtk.Builder()
            self._ui.add_from_file( self.get_option("ui_file") )

            self._ui_title = self._ui.get_object("window1").get_title()


            # --------------- Список каталогов ---------------

            treeview1 = self._ui.get_object("treeview1")

            # add columns:
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Каталог", cell0, text=0)
            treeview1.append_column(col0)

            store = self._ui.get_object("liststore1")
            treeview1.set_model(store)


            # --------------- Список алгоритмов хеширования ---------------

            combo_hash = self._ui.get_object("combobox_hash")
            store = gtk.ListStore(
                gobject.TYPE_STRING,
            )
            combo_hash.set_model(store)
            cell = gtk.CellRendererText()
            combo_hash.pack_start(cell, True)
            combo_hash.add_attribute(cell, 'text', 0)

            for item in self.get_hash_algs():
                store.append([item])


            # --------------- Список одинаковых файлов ---------------

            treeview3 = self._ui.get_object("treeview3")

            # add columns:
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№ хеша", cell0, text=0)
            treeview3.append_column(col0)
            
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№ файла", cell0, text=1)
            treeview3.append_column(col0)
            
            cell_rend = widgets.CellRendererButton()
            col0 = gtk.TreeViewColumn("Удалить", cell_rend, callable=2, text=7, xpad=8, ypad=9)
            treeview3.append_column(col0)
            
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Дата изменения", cell0, text=3)
            treeview3.append_column(col0)
            
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Размер", cell0, text=4)
            treeview3.append_column(col0)
            
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("MIME", cell0, text=5)
            treeview3.append_column(col0)
            
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Файл", cell0, text=6)
            treeview3.append_column(col0)
            
            #store = self._ui.get_object("treestore1")
            store = gtk.TreeStore(
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_PYOBJECT,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_INT,
                gobject.TYPE_INT,
                gobject.TYPE_INT,
            )
            treeview3.set_model(store)


            # --------------- Список похожих картинок ---------------

            treeview2 = self._ui.get_object("treeview2")

            # add columns:
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№ изображения", cell0, text=0)
            treeview2.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№ похожего", cell0, text=1)
            treeview2.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Название", cell0, text=2)
            treeview2.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Процент похожести", cell0, text=3)
            treeview2.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Очки качества", cell0, text=4)
            treeview2.append_column(col0)

            #store = self._ui.get_object("treestore1")
            store = gtk.TreeStore(
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
            )
            treeview2.set_model(store)


            # --------------- Список похожих архивов картинок ---------------

            treeview4 = self._ui.get_object("treeview4")

            # add columns:
            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№1", cell0, text=0)
            treeview4.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("№2", cell0, text=1)
            treeview4.append_column(col0)

            cell_rend = widgets.CellRendererButton()
            col0 = gtk.TreeViewColumn("Удалить", cell_rend, callable=2, text=7)
            treeview4.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Название", cell0, text=3)
            treeview4.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Изображений", cell0, text=4)
            treeview4.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Кол-во похожих", cell0, text=5)
            treeview4.append_column(col0)

            cell0 = gtk.CellRendererText()
            col0 = gtk.TreeViewColumn("Очки качества", cell0, text=6)
            treeview4.append_column(col0)

            #store = self._ui.get_object("treestore1")
            store = gtk.TreeStore(
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_PYOBJECT,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
                gobject.TYPE_STRING,
            )
            treeview4.set_model(store)


            # ---------------  ---------------

            filter = ",".join(self._options["filter_in"])
            self._ui.get_object("entry_filter_in").set_text(filter)
            
            filter = ",".join(self._options["filter_out"])
            self._ui.get_object("entry_filter_out").set_text(filter)
            
            ff = self._ui.get_object("filefilter_project")
            ff.set_name("Projects")
            ff.add_pattern("*.db")
            
            self._ui.connect_signals(self)
        return self._ui
    

    def match_func(self, model, iter, data):
        column, key = data # data is a tuple containing column number, key
        value = model.get_value(iter, column)
        return value == key
    
    def search(self, model, iter, func, data):
        while iter:
            if func(model, iter, data):
                return iter
            result = self.search(model, model.iter_children(iter), func, data)
            if result: return result
            iter = model.iter_next(iter)
        return None
    
    
    def update_ui_stats( self ):
        
        stats = self.get_stats().get_update()

        if not stats:
            return stats

        ui = self.get_ui()
        
        gobject.idle_add( ui.get_object("label_dirs").set_label, "%s" % stats["directories_count"] )
        gobject.idle_add( ui.get_object("label_dirs_searched").set_label, "%s" % stats["directories_searched"] )
        
        gobject.idle_add( ui.get_object("label_files").set_label, "%s" % stats["files_count"] )
        gobject.idle_add( ui.get_object("label_files_filtered").set_label, "%s" % stats["files_filtered"] )
        gobject.idle_add( ui.get_object("label_hashed").set_label, "%s" % stats["hashed_count"] )
        gobject.idle_add( ui.get_object("label_errors").set_label, "%s" % stats["errors_count"] )
        gobject.idle_add( ui.get_object("label_unique").set_label, "%s" % stats["unique_count"] )
        gobject.idle_add( ui.get_object("label_nonunique").set_label, "%s" % stats["nonunique_count"] )

        gobject.idle_add( ui.get_object("label_archives").set_label, "%s" % stats["archives_count"] )
        gobject.idle_add( ui.get_object("label_archives_processed").set_label, "%s" % stats["archives_processed"] )
        gobject.idle_add( ui.get_object("label_images").set_label, "%s" % stats["images_count"] )
        gobject.idle_add( ui.get_object("label_images_processed").set_label, "%s" % stats["images_processed"] )

        if stats["files_size"]:
            p_all = stats["readed_size"] * 1.0 / stats["files_size"]
        else:
            p_all = 0
        pb_all = p_all
        if pb_all < 0:
            pb_all = 0
        if pb_all > 1:
            pb_all = 1
        gobject.idle_add( ui.get_object("progressbar_all").set_fraction, pb_all )


        if stats["nonunique_count"]:
            p_un = stats["nonunique_count_now"] * 1.0 / stats["nonunique_count"]
        else:
            p_un = 0
        if p_un < 0:
            p_un = 0
        if p_un > 1:
            p_un = 1
        gobject.idle_add( ui.get_object("progressbar_nonuniq").set_fraction, p_un )

        nuq_sz, nuq_un = self.format_file_size_si( stats["nonunique_size"] )
        nuqn_sz, nuqn_un = self.format_file_size_si( stats["nonunique_size_now"] )

        gobject.idle_add( ui.get_object("progressbar_nonuniq").set_text,
            "Сейчас: %d (%0.3f%s); Найдено: %d (%0.3f%s)" % (
                stats["nonunique_count_now"], nuqn_sz, nuqn_un,
                stats["nonunique_count"], nuq_sz, nuq_un,
                )
        )

        asz, au = self.format_file_size_si( stats["files_size"] )
        rsz, ru = self.format_file_size_si( stats["readed_size"] )

        if not len(self._last_stats):
            self._last_stats.update(stats)
            self._last_stats["start_size"] = stats["real_readed_size"]
            self._last_stats["start_time"] = time()-1
            self._last_stats["time"] = time()-1

        if stats["files_size"] != stats["readed_size"]:

            stats["time"] = time()

            bs = stats["real_readed_size"] - self._last_stats["start_size"]
            if bs > 0 and stats["time"] > self._last_stats["start_time"]:
                bs /= stats["time"] - self._last_stats["start_time"]
            else:
                bs = 0.1

            sps, spu = self.format_file_size_si( bs )
            spu += "/сек"

            if not bs:
                bs = 0.1
            rts = (stats["files_size"] - stats["readed_size"]) / bs

            gobject.idle_add( ui.get_object("progressbar_all").set_text,
                "Все файлы: %0.2f%% : %0.3f%s из %0.3f%s, %0.1f%s, ETA: %s" % (
                p_all*100, rsz, ru, asz, au, sps, spu, timedelta(seconds = rts))
            )
        else:
            gobject.idle_add( ui.get_object("progressbar_all").set_text,
                "Все файлы: %0.2f%% : %0.3f%s из %0.3f%s, Заняло: %s" % (
                    p_all*100, rsz, ru, asz, au, timedelta(seconds = (self._last_stats['time'] - self._last_stats['start_time'])))
            )

        hashing_files = stats["hashing_file"]

        for device, item in hashing_files.items():
            if item["size"]:
                p_cur = item["readed"] * 1.0 / item["size"]
            else:
                p_cur = 0
            pb_cur = p_cur
            if pb_cur < 0:
                pb_cur = 0
            if pb_cur > 1:
                pb_cur = 1
            gobject.idle_add( self._get_file_progress(device).set_fraction, pb_cur )

            file_sz, file_u = self.format_file_size_si( item["size"] )
            file_rsz, file_ru = self.format_file_size_si( item["readed"] )

            if item["size"] != item["readed"]:

                stats["htime"] = time()

                file_bs = item["readed"]
                if file_bs > 0 and stats["htime"] > item["start_time"]:
                    file_bs /= stats["htime"] - item["start_time"]
                else:
                    file_bs = 0.1

                file_sps, file_spu = self.format_file_size_si( file_bs )
                file_spu += "/сек"

                if not file_bs:
                    file_bs = 0.1
                file_rts = (item["size"] - item["readed"]) / file_bs


                gobject.idle_add( self._get_file_label(device).set_text,
                    "Хеш для: %s" % ( item["name"], )
                )

                gobject.idle_add( self._get_file_progress(device).set_text,
                    "Вычисление: %0.2f%% : %0.3f%s из %0.3f%s, %0.1f%s, ETA: %s" % (
                    p_cur*100, file_rsz, file_ru, file_sz, file_u, file_sps, file_spu,
                    timedelta(seconds = file_rts))
                )
            else:
                gobject.idle_add( self._get_file_progress(device).set_text,
                    "Хеш: %0.2f%% : %0.3f%s из %0.3f%s" % (
                        p_cur*100, file_rsz, file_ru, file_sz, file_u)
                )

            pass


        p_arch = 0

        images_archive = stats["images_archive"]
        if images_archive:

            item = images_archive

            if item["count"]:
                p_cur = item["processed"] * 1.0 / item["count"]
            else:
                p_cur = 0
            pb_cur = p_cur
            if pb_cur < 0:
                pb_cur = 0
            if pb_cur > 1:
                pb_cur = 1
            gobject.idle_add( self._get_archive_progress("0").set_fraction, pb_cur )

            gobject.idle_add( self._get_archive_label("0").set_text,
                "Архив: %s" % ( item["name"], )
            )

            if item["count"] != item["processed"]:

                stats["itime"] = time()

                item_bs = item["processed"]
                if item_bs > 0 and stats["itime"] > item["start_time"]:
                    item_bs /= stats["itime"] - item["start_time"]
                else:
                    item_bs = 0.1

                if not item_bs:
                    item_bs = 0.1
                item_rts = (item["count"] - item["processed"]) / item_bs

                gobject.idle_add( self._get_archive_progress("0").set_text,
                    "Изображения: %0.2f%% : %s из %s, ETA: %s" % (
                        p_cur*100, item["processed"], item["count"], timedelta(seconds=item_rts))
                )
            else:
                gobject.idle_add( self._get_archive_progress("0").set_text,
                    "Изображения: %0.2f%% : %s из %s" % ( p_cur*100, item["processed"], item["count"], )
                )


            p_cur_cur = p_cur
            if stats["archives_count"]:
                p_cur = stats["archives_processed_size"] * 1.0 / stats["archives_size"]
            else:
                p_cur = 0
            pb_cur = p_cur
            if pb_cur < 0:
                pb_cur = 0
            if pb_cur > 1:
                pb_cur = 1
            gobject.idle_add( self._get_archive_progress("all").set_fraction, pb_cur )

            p_arch = p_cur

            gobject.idle_add( self._get_archive_label("all").set_text,
                "Архивы:"
            )

            if stats["archives_count"] != stats["archives_processed"]:

                stats["atime"] = time()

                item_bs = stats["archives_processed_size"]
                if item_bs > 0 and stats["atime"] > self._last_stats["start_time"]:
                    item_bs /= stats["atime"] - self._last_stats["start_time"]
                else:
                    item_bs = 0.1

                item_as, item_au = self.format_file_size_si( stats["archives_size"] )

                item_ps, item_pu = self.format_file_size_si( stats["archives_processed_size"] )

                item_sps, item_spu = self.format_file_size_si( item_bs )
                item_spu += "/сек"

                if not item_bs:
                    item_bs = 0.1
                item_rts = (stats["archives_size"] - stats["archives_processed_size"]) / item_bs

                gobject.idle_add( self._get_archive_progress("all").set_text,
                    "Архивы: %0.3f%% : %.3f (%.2f%s) из %s (%.2f%s) ~ %.2f%s, ETA: %s" % (
                        p_cur*100,
                        stats["archives_processed"]+p_cur_cur,
                        item_ps, item_pu,
                        stats["archives_count"],
                        item_as, item_au,
                        item_sps, item_spu,
                        timedelta(seconds=item_rts))
                )
            else:
                gobject.idle_add( self._get_archive_progress("all").set_text,
                    "Архивы: %0.2f%% : %s из %s" % ( p_cur*100, stats["archives_processed"], stats["archives_count"], )
                )


        title = ui.get_object("window1").get_title()
        new_title = "[ %.2f %%, %.2f %% ], %s" % ( p_all*100, p_arch*100, self._ui_title, )
        if title != new_title:
            gobject.idle_add( ui.get_object("window1").set_title, new_title )


        # Update last stats
        self._last_stats.update(stats)

        return stats


    def _clean_progress_ui(self):
        ui = self.get_ui()
        main_vbox = ui.get_object("vbox_files_progress")
        for child in main_vbox.get_children():
            child.destroy()
        self._file_lbl = {}
        self._file_prog = {}

        main_vbox = ui.get_object("vbox_archive_progress")
        for child in main_vbox.get_children():
            child.destroy()
        self._archive_lbl = {}
        self._archive_prog = {}

        return


    def _add_file_progress_ui(self, device):
        ui = self.get_ui()

        main_vbox = ui.get_object("vbox_files_progress")

        vbox = gtk.VBox()

        lbl = gtk.Label("Файл:")
        lbl.set_alignment(0, 0.5)
        lbl.set_name("label_current_file_%s" % device)
        lbl.show()
        vbox.pack_start(lbl)

        prog = gtk.ProgressBar()
        prog.set_name("progressbar_file_%s" % device)
        prog.set_show_text(True)
        prog.set_pulse_step(0.01)
        prog.show()
        vbox.pack_start(prog)

        vbox.show()
        main_vbox.pack_start(vbox)

        self._file_prog[ device ] = prog
        self._file_lbl[ device ] = lbl

        return


    def _add_archive_progress_ui(self, device):
        ui = self.get_ui()

        main_vbox = ui.get_object("vbox_archive_progress")

        vbox = gtk.VBox()

        lbl = gtk.Label("Файл:")
        lbl.set_alignment(0, 0.5)
        lbl.set_name("label_current_archive_%s" % device)
        lbl.show()
        vbox.pack_start(lbl)

        prog = gtk.ProgressBar()
        prog.set_name("progressbar_archive_%s" % device)
        prog.set_show_text(True)
        prog.set_pulse_step(0.01)
        prog.show()
        vbox.pack_start(prog)

        vbox.show()
        main_vbox.pack_start(vbox)

        self._archive_prog[ device ] = prog
        self._archive_lbl[ device ] = lbl

        return


    def _get_file_progress(self, device):
        if not self._file_prog.has_key(device):
            self._add_file_progress_ui(device)
        return self._file_prog[ device ]


    def _get_archive_progress(self, device):
        if not self._archive_prog.has_key(device):
            self._add_archive_progress_ui(device)
        return self._archive_prog[ device ]


    def _get_file_label(self, device):
        if not self._file_lbl.has_key(device):
            self._add_file_progress_ui(device)
        return self._file_lbl[ device ]


    def _get_archive_label(self, device):
        if not self._archive_lbl.has_key(device):
            self._add_archive_progress_ui(device)
        return self._archive_lbl[ device ]


    def update_ui( self ):
        
        #print("update_ui: BEGIN" )
        
        if self._started and self.get_stats().is_updated():

            stats = self.update_ui_stats()

            if not stats:
                return self._thread_ui_run

            stop = False

            if stats["files_count"] > 0 and stats["directories_searched"] != stats["directories_count"]:
                stop = True

            if stats["files_filtered"] > 0 and stats["files_processed"] != stats["files_filtered"]:
                stop = False

            if stats["archives_count"] > 0 and stats["archives_processed"] != stats["archives_count"]:
                stop = False

            if 'time' not in stats:
                stop = False
            elif stats['time'] - self._last_stats['start_time'] < 5 and stop:
                stop = False

            if stop:
                self.get_ui().get_object("window1").set_title(
                    "%s" % self._ui_title )

                self.update_ui_stats()
                self.get_ui().get_object("button_start").emit("toggled")

        #print("update_ui: END" )
        return self._thread_ui_run
    
    def do_start( self ):
        
        #print("do_start: BEGIN")

        self.get_stats().reset()
        self._last_stats = {}

        p = self.get_db()
        options = p.query("get_options", ( ))
        
        if u"directories" not in options:
            options["directories"] = self._options["directories"]
        else:
            options["directories"] = json.loads(options[u"directories"])

        
        print("do_start: options=%r" % options)
        

        p.query("clean", (), False)

        dirs_req = self.getTaskManager().get_request().getScanDirectory()

        for path in options["directories"]:
            st = os.stat(path)
            dirs_req.scan( st.st_dev, None, "", path )
        
        self._started = True
        
        #print("do_start: END")
        
        return True
    
    def do_stop( self ):

        if self._started:

            self.getTaskManager().get_request().stop()

            self._clean_progress_ui()

            print("Stats:")
            pprint(self.get_stats().get_update())
            self._started = False
        return True
    
    def do_stop_ui( self ):
        if self._thread_ui:
            print("Stop UI thread...")
            self._thread_ui_run = False
            self._thread_ui = None
    
    def do_quit( self ):
        self.do_stop()
        self.do_stop_ui()

        if self._th_dup_images:
            print("Stop dup images thread...")
            self._th_dup_images.stop_event.set()
            print("Wait dup images thread...")
            self._th_dup_images.stop_event.wait()
            while self._th_dup_images.isAlive():
                sleep(0.01)

        if self._th_dup_arch:
            print("Stop dup archives thread...")
            self._th_dup_arch.stop_event.set()
            print("Wait dup archives thread...")
            self._th_dup_arch.stop_event.wait()
            while self._th_dup_arch.isAlive():
                sleep(0.01)


        print("Send task manager quit...")
        self.getTaskManager().quit()
        print("Wait task manager quit...")
        while self.getTaskManager().get_request().ping() == "pong":
            sleep(0.01)

        print("Hide window...")
        self.get_ui().get_object("window1").hide()
        print("GTK main quit...")
        gtk.main_quit()
        print("GTK main quited...")


    def run( self ):

        self.getTaskManager().start_service()

        self.load_project()

        gtk.gdk.threads_init()
        
        gtk.gdk.threads_enter()
        
        self._thread_ui = gobject.timeout_add( 100, self.update_ui )
        
        self.get_ui().get_object("window1").show()
        
        gtk.main()
        gtk.gdk.threads_leave()


    def on_button_start_toggled( self, widget, data = None):
        widget.set_sensitive(False)
        if self._started:
            self.do_stop()
            widget.set_label( gtk.STOCK_GO_FORWARD )
        else:
            self.do_start()
            widget.set_label( gtk.STOCK_STOP )
        widget.set_sensitive(True)


    def add_directory( self, dir ):
        store = self.get_ui().get_object("liststore1")
        for row in store:
            if row[0] == dir:
                return False
        store.append( [ dir ] )
        self.save_directories()
        return

    def save_directories( self ):
        store = self.get_ui().get_object("liststore1")
        dirs = []
        for row in store:
            dirs.append("%s" % row[0])
            
        p = self.get_db()
        p.query("save_option", ( "directories", json.dumps(dirs), ), False)
        return


    def unload_project( self ):
        
        self.save_project()
        
        store = self.get_ui().get_object("liststore1")
        store.clear()
        
        treeview3 = self._ui.get_object("treeview3")
        store = treeview3.get_model()
        store.clear()
        
        self.get_ui().get_object("progressbar_all").set_fraction( 0.0 )

        filter = ",".join(self._options["filter_in"])
        self.get_ui().get_object("entry_filter_in").set_text(filter)
        
        filter = ",".join(self._options["filter_out"])
        self.get_ui().get_object("entry_filter_out").set_text(filter)

        self.get_ui().get_object("checkbutton_delete_to_trash").set_active(self._options["delete_to_trash"])
        return
    
    def save_project( self ):
        
        self.save_directories()
        
        p = self.get_db()

        filter = self.get_ui().get_object("entry_filter_in").get_text()
        p.query("save_option", ( "filter_in", json.dumps(filter.split(",")) ), False )
        
        filter = self.get_ui().get_object("entry_filter_out").get_text()
        p.query("save_option", ( "filter_out", json.dumps(filter.split(",")) ), False )

        p.query("save_option", ( "delete_to_trash", self.get_ui().get_object("checkbutton_delete_to_trash").get_active() ), False )

        fn = self.get_ui().get_object("filechooserbutton_temp_folder").get_filename()
        p.query("save_option", ( "temp_directory", fn ), False )

        widget = self.get_ui().get_object("combobox_hash")
        model = widget.get_model()
        active = widget.get_active()

        if active >= 0:
            p.query("save_option", ( "hash_function", model[active][0] ), False )

        return True
    
    def load_project( self ):

        print("load_project: self._options:")
        pprint(self._options)

        p = self.get_db()
        options = p.query("get_options", ( ))

        print("load_project: options:")
        pprint(options)

        if options.has_key("temp_directory"):
            self._options["temp_directory"] = options["temp_directory"]
            self.get_ui().get_object("filechooserbutton_temp_folder").set_filename(self._options["temp_directory"])

        if options.has_key("filter_in"):
            filter = json.loads(options["filter_in"])
            self._options["filter_in"] = filter
            self.get_ui().get_object("entry_filter_in").set_text(",".join(filter))
        
        if options.has_key("filter_out"):
            filter = json.loads(options["filter_out"])
            self._options["filter_out"] = filter
            self.get_ui().get_object("entry_filter_out").set_text(",".join(filter))

        if options.has_key("delete_to_trash"):
            self._options["delete_to_trash"] = int(options["delete_to_trash"])
            self.get_ui().get_object("checkbutton_delete_to_trash").set_active(self._options["delete_to_trash"])

        if options.has_key("hash_function"):
            self._options["hash_function"] = options["hash_function"]

            widget = self.get_ui().get_object("combobox_hash")
            model = widget.get_model()

            count = 0
            iter = model.iter_children(None)
            while iter:
                item = model.get_value(iter, 0)
                if item == options["hash_function"]:
                    break

                count += 1
                iter = model.iter_next(iter)

            if iter:
                widget.set_active(count)
            else:
                widget.set_active(0)

        store = self.get_ui().get_object("liststore1")
        store.clear()
        
        treeview3 = self._ui.get_object("treeview3")
        store = treeview3.get_model()
        store.clear()
        
        # self.test_store()
        
        if not options.has_key("directories"):
            options["directories"] = self._options["directories"]
        else:
            options["directories"] = json.loads( options["directories"] )
        
        for dir in options["directories"]:
            self.add_directory( dir )

        #self._options.update(options)
        print("load_project: self._options:")
        pprint(self._options)

        return True
    
    
    def on_filechooserbutton_folder_file_set( self, widget, data = None):
        fn = widget.get_filename()
        self.add_directory( fn )
        return

    def on_filechooserbutton_temp_folder_file_set(self, widget, data = None):
        fn = widget.get_filename()
        p = self.get_db()
        self._options["temp_directory"] = fn
        p.query("save_option", ( "temp_directory", fn ), False)


    def on_button_del_clicked( self, widget, data = None):
        tree = self.get_ui().get_object("treeview1")
        sel = tree.get_selection()
        store, rows = sel.get_selected_rows()
        for row in rows:
            store.remove( store.get_iter(row) )
        self.save_directories()
        return

    def on_button_clean_data_clicked( self, widget, data = None ):
        print("button_clean_data")
        p = self.get_db()
        p.query("clean", (), False)
        self.get_stats().reset()
        self._last_stats = {}
        self.update_ui_stats()
        self._clean_progress_ui()


    def idle_button_del_file_clicked( self, widget, data = None):
        print("idle_button_del_file")
        gobject.idle_add( self.button_del_file_clicked, widget, data )

    def idle_button_del_dup_file_clicked( self, widget, data = None):
        print("idle_button_del_dup_file")
        gobject.idle_add( self.button_del_dup_file_clicked, widget, data )

    def button_del_file_clicked( self, widget, data = None):
        print("button_del_file")
        
        treeview = self._ui.get_object("treeview3")
        treeselection = treeview.get_selection()
        
        store, fiter = treeselection.get_selected()
        
        if fiter and store.iter_depth(fiter) > 0:
            fid = store.get_value(fiter, 1)
            path = store.get_value(fiter, 6)
            size = int(store.get_value(fiter, 10))

            print("-- remove file: id=%r, path=%r, size=%r" % (fid, path, size,))

            db_req = self.get_db()
            hash_id = db_req.query("get_file_hash_id", ( int(fid), ) )

            print("-- remove file: hash id=%r" % (hash_id,))

            if self.get_option("delete_to_trash"):
                try:
                    send2trash( path )
                except:
                    print("-- can't send 2 trash, removing...")
                    if os.path.exists(path):
                        os.unlink( path )
            else:
                if os.path.exists(path):
                    os.unlink( path )

            db_req.query("remove_file", ( fid, ), False )
            db_req.query("remove_file_images", ( fid, ), False )

            store.remove(fiter)

            self.get_stats().dec("nonunique_count", 1)
            self.get_stats().dec("nonunique_count_now", 1)
            self.get_stats().dec("nonunique_size_now", size)
            self.update_ui_stats()
            
            if hash_id:
                hiter = self.search( store, store.iter_children(None),
                    self.match_func, (0, str(hash_id),))
                if hiter:
                    count = 0
                    fiter = store.iter_children(hiter)
                    while fiter:
                        count += 1
                        fiter = store.iter_next(fiter)
                    if count <= 1:
                        store.remove(hiter)
        
        return


    def button_del_dup_file_clicked( self, widget, data = None):
        print("button_del_dup_file")

        treeview = self._ui.get_object("treeview4")
        treeselection = treeview.get_selection()

        store, fiter = treeselection.get_selected()

        if fiter and store.iter_depth(fiter) > 0:
            fid1 = store.get_value(fiter, 0)
            fid2 = store.get_value(fiter, 1)
            path = store.get_value(fiter, 3)

            print("-- remove file: id1=%r, id2=%r, path=%r" % (fid1, fid2, path,))

            db_req = self.get_db()

            if self.get_option("delete_to_trash"):
                try:
                    send2trash( path )
                except:
                    print("-- can't send 2 trash, removing...")
                    if os.path.exists(path):
                        os.unlink( path )
            else:
                if os.path.exists(path):
                    os.unlink( path )

            if fid1:
                db_req.query("remove_file", ( fid1, ), False )
                db_req.query("remove_file_images", ( fid1, ), False )
                db_req.query("remove_file_file2file", ( fid1, ), False )

            if fid2:
                db_req.query("remove_file", ( fid2, ), False )
                db_req.query("remove_file_images", ( fid2, ), False )
                db_req.query("remove_file_file2file", ( fid2, ), False )

            store.remove(fiter)

            if fid2:
                hiter = self.search( store, store.iter_children(None),
                    self.match_func, (0, str(fid1),))
                if hiter:
                    count = 0
                    fiter = store.iter_children(hiter)
                    while fiter:
                        count += 1
                        fiter = store.iter_next(fiter)
                    if count <= 1:
                        store.remove(hiter)

        return


    def on_button_find_dupfiles_clicked( self, widget, data = None):
        from worker.search_dupfiles import FindDupFiles
        th = FindDupFiles(args=(self, self.get_ui(), self.get_db(), self.get_stats(),))
        th.start()
        return


    def on_button_find_dupimages_clicked( self, widget, data = None):
        from worker.search_dupimages import FindDupImages
        self._th_dup_images = FindDupImages(args=(self, self.get_ui(), self.get_db(), self.get_stats(),))
        self._th_dup_images.start()
        return

    def on_button_find_duparchives_clicked( self, widget, data = None):
        from worker.search_duparchives import FindDupArchives
        self._th_dup_arch = FindDupArchives(args=(self, self.get_ui(), self.get_db(), self.get_stats(),))
        self._th_dup_arch.start()
        return

    def on_button_clean_clicked( self, widget, data = None):
        store = self.get_ui().get_object("liststore1")
        store.clear()
        return
    
    def on_button_quit_clicked( self, widget, data = None):
        print("button_quit")
        self.save_project()
        self.do_quit()
        return
    
    def on_window1_destroy_event( self, widget, data = None):
        print("window1_destroy")
        self.save_project()
        self.do_quit()
        return
    
    def on_entry_filter_in_focus_out_event( self, widget, data = None):
        filter = widget.get_text().split(",")
        p = self.get_db()
        self._options["filter_in"] = filter
        p.query("save_option", ( "filter_in", json.dumps(filter) ) )
        return
    
    def on_entry_filter_out_focus_out_event( self, widget, data = None):
        filter = widget.get_text().split(",")
        p = self.get_db()
        self._options["filter_out"] = filter
        p.query("save_option", ( "filter_out", json.dumps(filter) ), False )
        return

    def on_checkbutton_delete_to_trash_toggled(self, widget, data = None):
        p = self.get_db()
        self._options["delete_to_trash"] = widget.get_active()
        p.query("save_option", ( "delete_to_trash", widget.get_active() ), False )
        return

    def on_combobox_hash_changed(self, widget, data = None):
        p = self.get_db()

        model = widget.get_model()
        active = widget.get_active()

        if active >= 0:
            self._options["hash_function"] = model[active][0]
            p.query("save_option", ( "hash_function", model[active][0] ), False )
        return

    pass
